package com.web.uid;

import lombok.Data;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.springframework.util.Assert;

/**
 * 为uid 分配64位
 */
@Data
public class BitsAllocator {

    /**
     * 总计64位
     */
    public static final int TOTAL_BITS = 1 << 6;


    /**
     * 字节为：[sign-> timestampBits-> workerIdBits-> sequenceBits] = 64
     */
    private int signBits = 1;
    //时间戳位
    private final int timestampBits;
    //机器ID位
    private final int workerIdBits;
    //每秒下的并发序列位
    private final int sequenceBits;


    /**
     * workId & sequence 最大值
     */
    private final long maxTimestamp;
    private final long maxWorkerId;
    private final long maxSequence;

    /**
     *  timestamp & workerId 转移
     */
    private final int timestampShift;
    private final int workerIdShift;

    public BitsAllocator(int timestampBits, int workerIdBits, int sequenceBits)
    {
        //确保分配64位
        int allocateTotalBits = timestampBits + workerIdBits + sequenceBits + signBits;
        Assert.isTrue(allocateTotalBits == TOTAL_BITS, "allocate not enough 64 bits");

        // 初始化 bits
        this.timestampBits = timestampBits;
        this.workerIdBits = workerIdBits;
        this.sequenceBits = sequenceBits;

        // 初始化 max value
        this.maxTimestamp = ~(-1L << timestampBits);
        this.maxWorkerId = ~(-1L << workerIdBits);
        this.maxSequence = ~(-1L << sequenceBits);

        // 初始化 转移
        this.timestampShift = workerIdBits + sequenceBits;
        this.workerIdShift = sequenceBits;

    }

    /**
     * 根据 时间戳，机器id，并发序列 为uid分配位
     */
    public long allocate(long deltaSeconds, long workerId, long sequence) {
        return (deltaSeconds << timestampShift) | (workerId << workerIdShift) | sequence;
    }


    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
    }



}
